'''
This file is part of DopplerShift.

    DopplerShift is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DopplerShift is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DopplerShift.  If not, see <http://www.gnu.org/licenses/>.
'''

from twisted.web.error import Error
import urllib
import logging
from twisted.web.client import getPage
from dopplershift.core.patterns.mapping import DSMapObject
from dopplershift.core.containers.mediator import getMediator
from dopplershift.collector.http import REQUEST_METHOD_GET, REQUEST_METHOD_POST
from twisted.python import log
from lxml import etree

logger = logging.getLogger(__name__)

class RemoteCall:
    _call_url = None
    def __init__(self, call_xml_info, authInfo):
        self._call = call_xml_info
        self._response_id = None
        self._request_id = None
        self._authInfo = authInfo
        self._headers = {
                         'X-DopplerShift-Format': call_xml_info.data_content_type
                         }
    def _prepareHttpArgs(self, args):
        result = []
        for el in args:
            cnt = len(args[el])
            if cnt > 1:
                for val in args[el]:
                    result.append((el, val))
            elif cnt > 0:
                result.append((el, args[el][0]))
        return result
    def call(self, url_params, method=REQUEST_METHOD_GET, request_params=None):
        if self._response_id == None or self._request_id == None:
            raise
        
        
        self._postdata = None
        request = getMediator().get('CollectorRequests').get(self._request_id)
        self._cookies = request.received_cookies
        args = self._prepareHttpArgs(request.args)
        
        self._headers.update(request.HEADERS)
        if len(args) > 0:
            r =  urllib.urlencode(args)
            if method == REQUEST_METHOD_GET:
                '''
                Modify url for get method processing. 
                '''
                self._call_url = self._call.getUrl(url_params, request_params, base_args=args)
            elif method == REQUEST_METHOD_POST:
                '''
                Modify body for postdata
                '''
                self._postdata = r
                self._call_url = self._call.getUrl(url_params, request_params)
        else: self._call_url = self._call.getUrl(url_params, request_params)

        if self._call.isCaching():
            return self.callCache(method)
        self.callService(method)
    def callCache(self, method):
        getMediator().get("CacheBackend").getCache(self.cacheAnswer, self._get_cache_key(), method)
    def cacheAnswer(self, result, method, local_value=True):
        if not result:
            return self.callService(method, local_value=False)
        getMediator().get("CacheBackend").set(self._get_cache_key(), result, self._get_cache_time(), isMissed=True)
        self.catchCallResponse(result, uncache=False, local_value=True)
    def callService(self, method, local_value=True):
        d = getPage(
                str(self._call_url),
                method=method,
                timeout=10,
                postdata=self._postdata,
                headers=self._headers,
                cookies=self._cookies
                ).addCallback(
                               callback=self.catchCallResponse, local_value=local_value)
        d.addErrback(self.catchCallError)
    def _getEventManager(self): 
        em = getMediator().get('CollectorHandlers').get(self._response_id)
        if em == None:
            logger.error("EVENT MANAGER IS NULL %s"%self._response_id)
            logger.error("%s"%self._call_url)
        return em
    def _get_cache_key(self):
        cache_key = "%s_%s"%(self._call.getID(), self._call_url.replace('http://', ''))
        return cache_key
    def _get_cache_time(self):
        return self._call.getCachingTime()
    def storedToCache(self, cache_key):
        logger.debug("stored to cache %s"%cache_key)
    def catchCallResponse(self, data, uncache=False, local_value=True):
        if self._call.isCaching():
            if uncache == False:
                cb = getMediator().get("CacheBackend")
                cb.setToCache(self.storedToCache, self._get_cache_key(), self._get_cache_time(), data )
            if local_value == False:
                getMediator().get("CacheBackend").setToLocalCache(self.storedToCache, self._get_cache_key(), self._get_cache_time(), data )
        answer = DSMapObject(body=data, id=self._call.getNodeName(), code=200)
        self._getEventManager().signal("RemoteServiceAnswer", answer)
    def catchCallError(self, error):
        answer = DSMapObject(body="<error />", id=self._call.getNodeName(), code=200)
        if self._call.exception(error.value.status): 
            answer.code = error.value.status
        self._getEventManager().signal("RemoteServiceAnswer", answer)
    def setResponseId(self, response_id):
        self._response_id = response_id
    def setRequestId(self, request_id):
        self._request_id = request_id
    